<?php
/**
 * Copyright (c) 2006-2008, Julien PORTALIER
 * http://featherphp.googlecode.com/
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 */

/**
 * Interface to the HTTP protocol.
 */
class HTTP
{
	protected static $codes;
	
	public    static $method;
	public    static $is_ajax;
	public    static $ajax;
	public    static $referer;
	
	/**
	 * Checks if User-Agent explicitly claims to support a mimetype.
	 * Wildcards are discarded (since support isn't explicit).
	 * 
	 * It can be used for instance to check if the requesting browser
	 * claims to support the application/xhtml+xml mimetype, which
	 * permits to serve content as XHTML + SVG; MathML, etc. or just
	 * plain HTML (MSIE, mostly).
	 * 
	 * \code
	 * if (HTTP::accept('application/xhtml+xml'))
	 * {
	 *   header('Content-Type: application/xhtml+xml; charset=utf-8');
	 *   echo '<?xml version="1.0" encoding="utf-8"?>';
	 * }
	 * else {
	 *   header('Content-Type: text/html; charset=utf-8');
	 * }
	 * \encode
	 * 
	 * @return Boolean True if mimetype is supported
	 * @param $mimetype 
	 */
	static function accept($mimetype)
	{
		$accept = preg_split('/\s*[,;]\s*/', $_SERVER['HTTP_ACCEPT']);
		return in_array($mimetype, $accept);
	}
	
	/**
	 * Redirects to another URL.
	 * 
	 * @param $url    String  URL to redirect to.
	 * @param $status Integer HTTP status code.
	 */
	static function redirect($url='/', $status=null)
	{
		if (!is_null($status)) {
			self::status($status);
		}
		if (DEBUG < 1) {
			header("Location: $url");
		}	
		else
		{
			$status = $status ? $status : 200;
			echo "<p style=\"text-align: center; font-size: 20px;\"><strong>Redirect to: <a href=\"$url\">$url</a></strong> [status: $status]</p>";
		}
		exit;
	}
	
	/**
	 * Sets HTTP status.
	 * 
	 * @return String  Status description. 
	 * @param  $status Integer HTTP status.
	 */
	static function status($status)
	{
		header(self::get_status($status));
	}
	
	/**
	 * Returns a description for a HTTP status.
	 * 
	 * @return String  Status description. 
	 * @param  $status Integer HTTP status.
	 */
	static function get_status($status)
	{
		if (empty(self::$codes)) {
			self::$codes = parse_ini_file(FEATHER.'config'.DS.'status.ini.php');
		}
		return self::$codes[$status];
	}
	
	static function & decode_postbody($body=null)
	{
		$_DATA = array();
		
		# get body
		if (is_null($body))
		{
			/*
			$body = '';
			$std_input = fopen('php://input', 'r');
			while ($tmp = fread($std_input, 1024)) {
				$body .= $tmp;
			}
			fclose($std_input);
			*/
			$body = stream_get_contents(STDIN);
		}
		
		# parse it
		foreach(explode("&", $body) as $pair)
		{
			$pair = explode('=', $pair);
			
			# case: nested arrays
			preg_match_all('/\[(.*?)\]/', $pair[0], &$matches, PREG_SET_ORDER);
			if(!empty($matches))
			{
				# data
				preg_match('/^([^\[]+)\[/', $pair[0], &$var);
				$var = urldecode($var[1]);
				if (!isset($_DATA[$var])) {
					$_DATA[$var] = array();
				}
				$_tmp =& $_DATA[$var];
				
				# each [...]
				foreach($matches as $m)
				{
					if (!empty($m[1]))
					{
						$k = urldecode($m[1]);
						if (!isset($_tmp[$k])) {
							$_tmp[$k] = '';
						}
						$_tmp =& $_tmp[$k];
					}
					else {
						$_tmp =& $_tmp[];
					}
				}
				
				# set value (if any)
				$_tmp = isset($pair[1]) ? urldecode($pair[1]) : '';
				continue;
			}
			
			# case: just a variable (with or without value)
			$_DATA[$pair[0]] = isset($pair[1]) ? urldecode($pair[1]) : '';
		}
		return $_DATA;
	}
	
	/**
	 * Downloads a file from the given URL into a local file.
	 * 
	 * @return Boolean
	 * @param $url String
	 * @param $path String
	 */
	static function download($url, $path)
	{
		if (($file_from = @fopen($url, 'r')) !== false)
		{
			if (($file_to = @fopen($path, 'w')) !== false)
			{
				while (!feof($file_from))
				{
					# 1160 = one TCP/IP packet
					$buff = fgets($file_from, 1160);
					fwrite($file_to, $buff);
				}
				fclose($file_from);
				fclose($file_to);
				return true;
			}
			fclose($file_from);
		}
		return false;
	}
	
	/**
	 * Runs an HTTP request and returns response.
	 * 
	 * @return String
	 * @param $url String
	 * @param $params Array[optional]
	 */
	static function request($url, array &$params=null)
	{
		$query = empty($params) ? '' : http_build_query($params);
		if (($req = @fopen("$url?$query", 'r')) !== false)
		{
			$buf = '';
			while (!feof($req))
			{
				# 1160 = one TCP/IP packet
				$buff .= fgets($req, 1160);
			}
			fclose($req);
			return $buf;
		}
		return false;
	}
}

HTTP::$method  = isset($_SERVER['REQUEST_METHOD']) ? strtoupper($_SERVER['REQUEST_METHOD']) : null;
HTTP::$is_ajax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) and $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest');
HTTP::$ajax    = HTTP::$is_ajax;
HTTP::$referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;

?>